#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>

#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELTM " \t"
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 44

int lastcode = 0;//退出码
int quit = 0;
extern char **environ;
char commandline[LINE_SIZE];
char *argv[ARGC_SIZE];
char pwd[LINE_SIZE];


//自定义环境变量表
char myenv[LINE_SIZE];

const char* getusername()
{
  return getenv("USER");
}

const char* getHostname()
{
  return getenv("HOSTNAME");
}

void getpwd()
{
  getcwd(pwd,sizeof(pwd));
}

void interact(char *cline,int size)
{
  getpwd();
  printf(LEFT"%s@%s %s"RIGHT""LABLE" ",getusername(),getHostname(),pwd);   
  char* s = fgets(cline,size,stdin);
  assert(s);
  (void)s;// ?

  cline[strlen(cline)-1] = '\0';
}


int splitstring(char cline[],char * _argv[])
{
  int i = 0;
  _argv[i++] = strtok(cline,DELTM);
  while(_argv[i++] = strtok(NULL,DELTM));
  return i - 1;
}

int buildCommand(char *_argv[],int _argc)
{
  if(_argc == 2 && strcmp(_argv[0],"cd") == 0)
  {
    chdir(argv[1]);//chdir函数进入argv[1]所指的目录中
    getpwd();
    sprintf(getenv("PWD"),"%s",pwd);

    return 1;
  }
  else if(_argc == 2 && strcmp(_argv[0],"export") == 0)
  {
   //export指令，-p 显示shell中所以的环境变量，export 变量名，添加环境变量    //           -n 变量名 删除环境变量
   strcpy(myenv,_argv[1]);
   putenv(myenv);//将自己的环境变量，加入到系统的环境变量表中，注意自己
                //定义的环境变量的储存空间不能是一个临时空间，不然查找是会出现野指针
  
   return 1;
  }
  else if(_argc == 2 && strcmp(_argv[0],"echo") == 0)
  {
    if(strcmp(_argv[1],"$?") == 0)//$? 获取退出码
    {
      printf("%d\n",lastcode);
      lastcode = 0;//为0代表程序正常运行，非0代表异常
    }
    else if(*_argv[1] == '$')
    {
      char *val = getenv(_argv[1]+1);
      if(val)
      {
        printf("%s\n",val);
      }
    }
    else
    {
      printf("%s\n",_argv[1]);
    }

    return 1;
  }
  if(strcmp(_argv[0],"ls") == 0)
  {
    _argv[_argc++] = "--color";
    _argv[_argc] = NULL;
  }
  return 0;
}


void NormalExcute(char *_argv[])
{
  pid_t id = fork();
  if(id < 0)
  {
    perror("fork");
    return;
  }
  else if(id == 0)
  {
    execvp(_argv[0],_argv);
    exit(EXIT_CODE);//非正常运行退出运行
  }
  else
  {
    int status = 0;
    pid_t rid = waitpid(id,&status,0);
    if(rid == id)
    {
      lastcode = WEXITSTATUS(status);//WEXITSTATUS用于从子进程的终止状态中提取出退出状态码。
    }
  }
}

int main()
{
  while(!quit)
  {
    //1
    //2.交互问题，获得命令行
    interact(commandline,sizeof(commandline));

    //3.子串分割问题，解析命令行
    int argc = splitstring(commandline,argv);
    if(argc == 0) continue;

    //4.指令的判断
    int n = buildCommand(argv,argc);


    if(!n) NormalExcute(argv);
    
  }
  
  return 0;
}

